#include <ctype.h>
#include <getch.h>
#include <string.h>
#include <stdlib.h>

#include "tools.h"

void clear_screen(void) {
    system("clear");
}

void clear_stdin(void) {
    stdin->_IO_read_ptr = stdin->_IO_read_end;
}

char get_cmd(char start, char end, bool isshow) {
    clear_stdin();
    printf("请输入指令:");
    while (1) {
        char cmd = getch();
        if (start <= cmd && cmd <= end) {
            if (isshow)
                printf("%c\n", cmd);
            return cmd;
        }
    }
}

bool get_str(char* str, size_t size) {
    clear_stdin();
    size_t i = 0;
    while (i < size) {
        str[i] = getch();
        if (Esc == str[i])
            return false;
        if (Enter == str[i]) {
            if (i == 0) continue;
            break;
        }
        if (Backsapce == str[i]) {
            if (i > 0) {
                i--;
                printf("\b \b");
            }
            continue;
        }
        if (isalnum(str[i]) || str[i] == '.' || Space == str[i]) {
            printf("%c", str[i]);
            i++;
        }
    }
    str[i] = '\0';
    return true;
}

char get_sex(void) {
    clear_stdin();
    printf("请输入性别(女F,男M):");
    while (1) {
        char sex = getch();
        if ('F' == sex || 'M' == sex || 'm' == sex || 'f' == sex) {
            printf("%s\n", show_sex(sex));
            return sex;
        }
    }
}

char* show_sex(char sex) {
    switch (sex) {
    case 'F':
    case 'f':
        return "女";
    case 'm':
    case 'M':
        return "男";
    default:
        return "X";
    }
}

bool get_password(char* password, size_t min, size_t max, bool isshow) {
    clear_stdin();
    size_t i = 0;
    while (i < max) {
        password[i] = getch();
        if (Esc == password[i]) {
            return false;
        }
        if (Enter == password[i]) {
            if (i < min)
                continue;
            break;
        }
        if (Backsapce == password[i]) {
            if (i > 0) {
                i--;
                if (isshow) {
                    printf("\b \b");
                }
            }
            continue;
        }
        if (!isalnum(password[i]))
            continue;
        if (isshow)
            printf("*");
        i++;
    }
    password[i] = '\0';
    return true;
}

void anykey_continue(void) {
    hide_cursor();
    clear_stdin();
    // puts("~按任意键继续~");
    getch();
    show_cursor();
}

bool yes_or_no(void) {
    clear_stdin();
    printf("请选择(y/n):");
    while (1) {
        char cmd = getch();
        if ('y' == cmd || 'Y' == cmd) {
            return true;
        }
        if ('n' == cmd || 'N' == cmd) {
            return false;
        }
    }
}

void show_msg(char* msg, float sec) {
    print_color(msg, Blue);
    printf("\n");
    usleep(sec * 1000000);
}

void show_err(char* err) {
    printf("%s", err);
    exit(0);
}

void print_color(const char* msg, Color color) {
    printf("\033[01;%dm%s\033[00m", color, msg);
    fflush(stdout);
}

int init_id(const char* path, uint64_t arr[], size_t len) {
    if (!access(path, F_OK)) return 0;
    return save_data(path, arr, sizeof(arr[0]), len);
}

uint64_t get_id(const char* path, size_t index) {
    FILE* frwp = fopen(path, "r+");
    if (NULL == frwp) {
        printf("%s文件未初始化\n", path);
        return -1;
    }
    uint64_t id;
    fseek(frwp, index * sizeof(uint64_t), SEEK_SET);
    fread(&id, sizeof(uint64_t), 1, frwp);
    id++;
    fseek(frwp, index * sizeof(uint64_t), SEEK_SET);
    fwrite(&id, sizeof(uint64_t), 1, frwp);
    fclose(frwp);
    return id - 1;
}

size_t save_data(const char* path, void* data, size_t size, size_t nmemb) {
    FILE* fwp = fopen(path, "w");
    if (NULL == fwp) {
        printf("无法创建文件%s\n", path);
        return 0;
    }
    size_t success = fwrite(data, size, nmemb, fwp);
    fclose(fwp);
    return success;
}

size_t gsuccess, gsize;
FILE* fp;

void saveNode(void* data) {
    gsuccess += fwrite(data, gsize, 1, fp);
}

size_t load_data(const char* path, void* data, size_t size, size_t nmemb) {
    FILE* frp = fopen(path, "r");
    if (NULL == frp) {
        printf("无法加载文件%s\n", path);
        return 0;
    }
    size_t success = fread(data, size, nmemb, frp);
    fclose(frp);
    return success;
}

size_t file_size(const char* path) {
    FILE* frp = fopen(path, "r");
    if (NULL == frp) {
        return -1;
    }
    fseek(frp, 0, SEEK_END);
    size_t bytes = ftell(frp);
    fclose(frp);
    return bytes;
}

void show_cursor(void) {
    printf("\033[?25h");
    fflush(stdout);
}

void hide_cursor(void) {
    printf("\033[?25l");
    fflush(stdout);
}

void set_cursor(int x, int y) {
    printf("\033[%d;%dH", x, y);
    fflush(stdout);
}

int split(char* src, char** dest, const char* separator) {
    //如果源文本未为空则无需分割
    if (src == NULL || strlen(src) == 0)
        return 0;
    //如果要分割的字符串为空那么不能分割
    if (separator == NULL || strlen(separator) == 0)
        return 0;
    //先分割一次
    char* pNext = strtok(src, separator);
    int count = 0;
    //如果还不为空 并且分割次数没有达到上限那么继续分割
    while (pNext != NULL) {
        //赋值并移到下一个字符串
        *dest++ = pNext;
        //计数器自增
        ++count;
        //继续获取字符串
        pNext = strtok(NULL, separator);
    }
    //返回成功的个数
    return count;
}

size_t strlen_in_terminal(char* src) {
    size_t cnt = 0;
    size_t chi = 0;
    while (*src) {
        if (*src < 0)
            chi++;
        if (*src > 0)
            cnt++;
        src++;
    }
    return cnt + chi / 3 * 2;
}

size_t strlen_until_blank(char* src) {
    size_t cnt = 0;
    size_t chi = 0;
    while (*src) {
        if (*src < 0)
            chi++;
        if (*src > 0)
            cnt++;
        src++;
        if (*src == Space)
            break;
    }
    return cnt + chi / 3 * 2;
}

size_t str_count_space(char* src) {
    size_t cnt = 0;
    while (*src++)
        if (*src == Space)
            cnt++;
    return cnt;
}

void time_add_days(struct tm* date, const int add_days) {
    const time_t one_day = 24 * 60 * 60;
    // Seconds since start of epoch --> 01/01/1970 at 00:00hrs
    time_t date_seconds = mktime(date) + (add_days * one_day);
    *date = *localtime(&date_seconds);
}

void time_add_months(struct tm* date, int add_months) {
    int mon[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int now_mon = date->tm_mon;
    int cnt = 0;
    bool flag = false;
    if (add_months < 0) {
        add_months *= -1;
        flag = true;
    }
    for (int i = now_mon; i < add_months + now_mon; i++) {
        int k = (i - 1) % 12;
        if (k < 0)
            k += 11;
        cnt += mon[k];
    }
    if (flag)
        cnt *= -1;
    time_add_days(date, cnt);
}

size_t number_len(int num) {
    size_t len = 1;
    if (num < 0)
        num *= -1;
    while (num > 9) {
        num /= 10;
        len++;
    }
    return len;
}

char* itoa(int value, char* str, int radix) {
    if (radix < 2 || radix > 16)
        return str;
    char* dest = str;
    char p[16] = "0123456789ABCDEF";
    char tmp[100] = {};
    size_t index = 0;

    int sum = value;

    if (value < 0) {
        *dest++ = '-';
        sum *= -1;
    }
    while (sum >= radix) {
        tmp[index++] = p[sum % radix];
        sum /= radix;
    }
    tmp[index++] = p[sum];
    while (index > 0)
        *dest++ = tmp[--index];
    *dest = '\0';
    return str;
}

char* time_now_str(char* str, int strlen)
{
    time_t now = time(NULL);
    strftime(str, strlen, "%Y-%m-%d %H:%M:%S", localtime(&now));
    return str;
}
